package geneComponent;

import java.util.*;

import util.Log;
import base.Item;
import base.Parameter;
import factory.Job;
import factory.Machine;
import factory.Schedule;

public abstract class Node extends Item implements Cloneable {
  
	protected Job job;
	protected Machine machine;
	protected Schedule schedule;
	
	private boolean rootNode=true;
	
    public Node(Parameter parameters) {
    	
		maxDepth = parameters.getValueToInt(Parameter.TYPE_MAX_DEPTH);
		depth = parameters.getValueToInt(Parameter.TYPE_DEPTH);
		arity = parameters.getValueToInt(Parameter.TYPE_ARITY);

		if(this instanceof Terminal) return;

		branches = new ArrayList<Node>();
		
		for (int i=0; i < arity; ++i) {
	
			branches.add(NodeFactory.getRandomNode(maxDepth, getChildDepth(), arity));
		}
    }
    
    public int getChildDepth() {
		return depth + 1;
	}
    
	public int getDepth() {
		return depth;
	}
	
    private Node root;

    private int maxDepth;

    private int depth;

    private int arity;

    private double resultValue;
    
    protected boolean terminal = false;

    protected ArrayList<Node> branches;
    
    public Node getNode(int i){
    	return branches.get(i);
    }
    
    public Node setNode(int i, Node node){
    	return branches.set(i, node);
    }
    
    public Node getChild(int index) { 
    	return branches.get(index);
    }
    
    public int getChildNumber() { 
    	return branches.indexOf(this);
    }
    
    protected void setResult(double value) {
    	resultValue = value;
    }
 
    public int getMaxDepth() {
        return maxDepth;
    }

    public int getArity() {
        return arity;
    }

    public double getResult() {
        return resultValue;
    }

    public boolean isTerminal() {
        return terminal;
    }

    public void setRoot(Node root) {
    	this.root = root;
    }

    public Node getRoot() {
        return root;
    }
	public Job getJob() {

		return job;
	}
	
	public void setJob(Job job) {
		
		if(this instanceof Function){
		
		for(Node n : branches){
			n.setJob(job);
			}
		}
		
		this.job = job;
	}
	
	public Machine getMachine() {
		return machine;
	}
	
	public void setMachine(Machine machine) {
		
		if(this instanceof Function){
			
			for(Node n : branches){
				n.setMachine(machine);
			}
		}
		this.machine = machine;
	}
	
	public void setSchedule(Schedule schedule, long currenTime) {
		
		if(this instanceof Function){
			
			for(Node n : branches){
				n.setSchedule(schedule, schedule.getCurrentTime());
			}
		}
		this.schedule = schedule;
	}
	
	public boolean isRootNode() {
		return rootNode;
	}

	public ArrayList<Node> getBranches() {
		return branches;
	}
	
	public void setBranches(ArrayList<Node> branches) {
		this.branches = branches;
	}
	
	
	
}